package com.gitee.deament.server.core.cli.db.str;

import cn.hutool.core.util.NumberUtil;
import com.gitee.deament.server.config.SystemConfig;
import com.gitee.deament.server.core.annotation.CliHander;
import com.gitee.deament.server.core.cli.AbstractCli;
import com.gitee.deament.server.core.data.ConnectData;
import com.gitee.deament.server.core.data.datatype.Value;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;

/**
 * INCRBYFLOAT key increment
 * 可用版本： >= 2.6.0
 * 时间复杂度： O(1)
 * 为键 key 储存的值加上浮点数增量 increment 。
 *
 * 如果键 key 不存在， 那么 INCRBYFLOAT 会先将键 key 的值设为 0 ， 然后再执行加法操作。
 *
 * 如果命令执行成功， 那么键 key 的值会被更新为执行加法计算之后的新值， 并且新值会以字符串的形式返回给调用者。
 *
 * 无论是键 key 的值还是增量 increment ， 都可以使用像 2.0e7 、 3e5 、 90e-2 那样的指数符号(exponential notation)来表示， 但是， 执行 INCRBYFLOAT 命令之后的值总是以同样的形式储存， 也即是， 它们总是由一个数字， 一个（可选的）小数点和一个任意长度的小数部分组成（比如 3.14 、 69.768 ，诸如此类)， 小数部分尾随的 0 会被移除， 如果可能的话， 命令还会将浮点数转换为整数（比如 3.0 会被保存成 3 ）。
 *
 * 此外， 无论加法计算所得的浮点数的实际精度有多长， INCRBYFLOAT 命令的计算结果最多只保留小数点的后十七位。
 *
 * 当以下任意一个条件发生时， 命令返回一个错误：
 *
 * 键 key 的值不是字符串类型(因为 Redis 中的数字和浮点数都以字符串的形式保存，所以它们都属于字符串类型）；
 *
 * 键 key 当前的值或者给定的增量 increment 不能被解释(parse)为双精度浮点数。
 *
 * 返回值
 * 在加上增量 increment 之后， 键 key 的值。
 * @author deament
 */
@CliHander(command = "INCRBYFLOAT")
public class INCRBYFLOATcli extends AbstractCli {
    @Override
    public void executeCli(ChannelHandlerContext channelHandlerContext, String command) {
        List<String> values = getValues(command);
        if (values.size() != 3) {
            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("ERR wrong number of arguments for 'INCRBY' command"));
            return;
        }
        int db = ConnectData.SELECT_DB_STORAGE.getUseDB(channelHandlerContext.channel().id().asLongText());
        String key=values.get(1);
        String increaseNum=values.get(2);
        if(!NumberUtil.isNumber(increaseNum)){
            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("ERR value is not an integer or out of range"));
        }
        BigDecimal increaseNumber= new BigDecimal(increaseNum) ;
        Value<String> stringData = SystemConfig.dbData.getStringData(db, key);
        Value<String> newValue= new Value<>();

        newValue.setValue(increaseNumber+"");
        if(stringData==null){
            SystemConfig.dbData.setStringData(db, key,newValue);
            channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(SystemConfig.dbData.getStringData(db, key).getValue()));
        } else{
            Date date = stringData.getExpirDateTime();
            if ((date.compareTo(new Date())) <= 0) {
                SystemConfig.dbData.setStringData(db, key,newValue);
                channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(SystemConfig.dbData.getStringData(db, key).getValue()));
                return;
            }
            if(NumberUtil.isInteger(stringData.getValue())){
                //TODO 线程安全的问题待解决
                newValue.setValue( increaseNumber.add(new BigDecimal(stringData.getValue())).toString());
                channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame(SystemConfig.dbData.getStringData(db, key).getValue()));
            }else{
                channelHandlerContext.channel().writeAndFlush(new TextWebSocketFrame("ERR value is not an integer or out of range"));
                return;

            }
        }
    }
}
